// **************************************************************
// Com ++ Framework by the C++ World
// Please report defects: mailto:compp@cplusplusworld.com
// Please visit: http://www.cplusplusworld.com/socketlibrary.html
// **************************************************************

#include <iostream>
#include <stdlib.h>
#include "ComPlusPlus/ComPlusPlus"

class Runner : public compp::Thread {

  protected:
   std::string MyName ;
  public:
   Runner() {
    std::cout << "Runner Created.\n";
   }
   ~Runner() {
    std::cout << "Runner Deleted.\n";
   }
   void * Run ( void *arg ) {
    MyName = (char *) arg;
    for ( int i = 0; i < 5; ++ i ) {
	syspp::Call::Sleep ( 1);
        std::cout << "Runner: " << MyName << "  i = " << i << "\n";
    }
    std::cout << "Runner: " << MyName << "\n";
    return NULL;
   }
};

static compp::Mutex CritMutex;

class RunnerCrit : public compp::Thread {

  protected:
   std::string MyName ;
  public:
   RunnerCrit() {
    std::cout << "Runner Created.\n";
   }
   ~RunnerCrit() {
    std::cout << "Runner Deleted.\n";
   }
   void * Run ( void *arg ) {
     compp::CriticalSection CS ( CritMutex );
     MyName = (char *) arg;
     for ( int i = 0; i < 5; ++ i ) {
       syspp::Call::Sleep ( 1);
       std::cout << "RunnerCritSect: " << MyName << "\n";
     }
     std::cout << "RunnerCritSect: " << MyName << "\n";
     return NULL;
   }
};


int main() {


  std::cout << "*** Three Threads. With Synchronisation ***\n";

  Runner *RunnerInst3 = new Runner ();
  Runner *RunnerInst4 = new Runner ();
  Runner *RunnerInst5 = new Runner ();

  RunnerInst3->Start ( (void *) "Thread 3 " );
  RunnerInst3->Join ( );

  RunnerInst4->Start ( (void *) "Thread 4 " );
  RunnerInst4->Join ( );
  RunnerInst5->Start ( (void *) "Thread 5 " );

  std::cout << "*** Two Threads. No synchronisation ***\n";
  Runner *RunnerInst1 = new Runner ();
  RunnerInst1->Start ( (void *) "Thread 1 " );
   
  Runner *RunnerInst2 = new Runner ();
  RunnerInst2->Start ( (void *) "Thread 2 " );

  syspp::Call::Sleep ( 10 );
  delete RunnerInst1;
  delete RunnerInst2;
  delete RunnerInst3;
  delete RunnerInst4;
  delete RunnerInst5;

  std::cout << "************ Critcal Section Test **************\n" ;
  RunnerCrit *RunnerCrit3 = new RunnerCrit ();
  RunnerCrit *RunnerCrit4 = new RunnerCrit ();
  RunnerCrit *RunnerCrit5 = new RunnerCrit ();

  RunnerCrit3->Start ( (void *) "Thread 3 " );
  RunnerCrit4->Start ( (void *) "Thread 4 " );
  RunnerCrit5->Start ( (void *) "Thread 5 " );

  syspp::Call::Sleep ( 10 );
  delete RunnerCrit3;
  delete RunnerCrit4;
  delete RunnerCrit5;

 return 0;
}
